package cn.iocoder.yudao.module.erp.service.saleorder;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.datapermission.core.util.DataPermissionUtils;
import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
import cn.iocoder.yudao.module.crm.dal.mysql.customer.CrmCustomerMapper;
import cn.iocoder.yudao.module.erp.controller.admin.saleorder.vo.*;
import cn.iocoder.yudao.module.erp.convert.goodswarehouselink.ErpGoodsWarehouseLinkConvert;
import cn.iocoder.yudao.module.erp.convert.saleorder.ErpSaleOrderGoodsConvert;
import cn.iocoder.yudao.module.erp.dal.dataobject.business.order.ordermethod.OrderMethodDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.business.order.orderproject.OrderProjectDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.business.tax.taxrate.TaxRateDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.business.warehouse.WarehouseDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.saleorder.SaleOrderDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.saleorder.SaleOrderGoodsDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.goods.GoodsDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.goodswarehouselink.GoodsWarehouseLinkDO;
import cn.iocoder.yudao.module.erp.dal.mysql.business.order.ordermethod.OrderMethodMapper;
import cn.iocoder.yudao.module.erp.dal.mysql.business.order.orderproject.OrderProjectMapper;
import cn.iocoder.yudao.module.erp.dal.mysql.business.tax.taxrate.TaxRateMapper;
import cn.iocoder.yudao.module.erp.dal.mysql.business.warehouse.WarehouseMapper;
import cn.iocoder.yudao.module.erp.dal.mysql.saleorder.SaleOrderGoodsMapper;
import cn.iocoder.yudao.module.erp.dal.mysql.saleorder.SaleOrderMapper;
import cn.iocoder.yudao.module.erp.dal.mysql.stock.goods.GoodsMapper;
import cn.iocoder.yudao.module.erp.dal.mysql.stock.goodswarehouselink.GoodsWarehouseLinkMapper;
import cn.iocoder.yudao.module.erp.dal.redis.no.ErpNoRedisDAO;
import cn.iocoder.yudao.module.erp.service.stock.goods.GoodsService;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.dal.mysql.user.AdminUserMapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.USER_NOT_EXISTS;

/**
 * 销售订单 Service 实现类
 *
 * @author maxuxu
 */
@Service
@Validated
@Slf4j
public class SaleOrderServiceImpl implements SaleOrderService {

    @Resource
    private SaleOrderMapper saleOrderMapper;
    @Resource
    private SaleOrderGoodsMapper saleOrderGoodsMapper;

    @Resource
    private GoodsMapper goodsMapper;

//    @Resource
//    private SequenceService sequenceService;

    @Resource
    private AdminUserMapper adminUserMapper;

    @Resource
    private WarehouseMapper warehouseMapper;

    @Resource
    private GoodsWarehouseLinkMapper goodsWarehouseLinkMapper;

    @Resource
    private OrderProjectMapper orderProjectMapper;

    @Resource
    private TaxRateMapper taxRateMapper;

    @Resource
    private OrderMethodMapper orderMethodMapper;

    @Resource
    private CrmCustomerMapper crmCustomerMapper;

    @Resource
    private ErpNoRedisDAO noRedisDAO;

    @Resource
    private ObjectMapper objectMapper;
    @Resource
    private GoodsService goodsService;
    @Resource
    private GoodsWarehouseLinkMapper inventoryMapper;
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createSaleOrder(SaleOrderSaveReqVO createReqVO) {
        // 插入
        SaleOrderDO saleOrder = BeanUtils.toBean(createReqVO, SaleOrderDO.class);
        if (StrUtil.isEmpty(saleOrder.getBillNo())) {
//            saleOrder.setBillNo(sequenceService.nextSequence("XS"));
            saleOrder.setBillNo(noRedisDAO.generate(ErpNoRedisDAO.SALE_ORDER_NO_PREFIX));
        }else {
            SaleOrderDO saleOrderDO = saleOrderMapper.selectByNo(saleOrder.getBillNo());
            if (ObjectUtil.isNotEmpty(saleOrderDO)) {
                throw exception(SALE_ORDER_NO_EXISTS);
            }
        }
        saleOrderMapper.insertSaleOrder(saleOrder);

        // 校验子表
        List<SaleOrderGoodsDO> saleOrderGoodsList = validateSaleGoods(createReqVO.getItems());
        // 插入子表
        createSaleOrderGoodsList(saleOrder.getId(), saleOrderGoodsList);
        // 返回
        return saleOrder.getId();
    }
    private List<SaleOrderGoodsDO> validateSaleGoods(List<SaleOrderSaveReqVO.Item> items) {
        List<Long> itemIds = convertList(items, SaleOrderSaveReqVO.Item::getGoodsId);
        goodsService.validProductList(itemIds);
        return ErpSaleOrderGoodsConvert.INSTANCE.convertSaveVOList(items);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateSaleOrder(SaleOrderSaveReqVO updateReqVO) {
        // 校验存在
        validateSaleOrderExists(updateReqVO.getId());
        // 更新
        SaleOrderDO updateObj = BeanUtils.toBean(updateReqVO, SaleOrderDO.class);
        saleOrderMapper.updateById(updateObj);
        // 校验子表
        List<SaleOrderGoodsDO> saleOrderGoodsList = validateSaleGoods(updateReqVO.getItems());
        // 更新子表
        updateSaleOrderGoodsList(updateReqVO.getId(), saleOrderGoodsList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteSaleOrder(Long id) {
        // 校验存在
        validateSaleOrderExists(id);
        // 删除
        saleOrderMapper.deleteById(id);

        // 删除子表
        deleteSaleOrderGoodsByOrderId(id);
    }

    @Override
    public void deleteAnySaleOrder(Collection<Long> ids) {
        saleOrderMapper.deleteBatchIds(ids);
        // 删除子表（通过删除order_id）
        deleteAnySaleOrderGoodsByOrderId(ids);
    }

    private void validateSaleOrderExists(Long id) {
        if (saleOrderMapper.selectById(id) == null) {
            throw exception(SALE_ORDER_NOT_EXISTS);
        }
    }

    private void validateSaleOrderBillNoUnique(String billNo, boolean isUpdateSupport, Map<String, Boolean> map) {
        // 校验编号是否唯一
        if (!isUpdateSupport && saleOrderMapper.selectByNo(billNo) != null && !map.get(billNo)) {
            throw exception(SALE_ORDER_EXISTS);
        }
    }

    private void validateWarehouseName(String warehouseName) {
        if (StrUtil.isBlank(warehouseName)) {
            throw exception(WAREHOUSE_NAME_IS_EMPTY);
        }
        if (warehouseMapper.selectByName(warehouseName) == null) {
            throw exception(WAREHOUSE_NOT_EXISTS);
        }
    }

    private void validateCustomer(String customerName) {
        if (StrUtil.isNotBlank(customerName) && crmCustomerMapper.selectOne(CrmCustomerDO::getName, customerName) == null) {
            throw exception(CUSTOMER_NOT_EXISTS);
        }
    }

    private void validateGoods(String code) {
        if (StrUtil.isBlank(code)) {
            throw exception(GOODS_CODE_IS_EMPTY);
        }
        if (goodsMapper.selectByCode(code) == null) {
            throw exception(GOODS_NOT_EXISTS);
        }
    }

    private void validateTaxRate(BigDecimal taxRate) { // todo: 这里的select方法最好抽离出来放入mapper中方便复用
        if (taxRateMapper.selectOne(TaxRateDO::getName, taxRate) == null) {
            throw exception(TAX_RATE_NOT_EXISTS);
        }
    }

    private void validateProject(String projectName) {
        if (!StrUtil.isBlank(projectName) && orderProjectMapper.selectOne(OrderProjectDO::getName, projectName) == null) {
            throw exception(ORDER_PROJECT_NOT_EXISTS);
        }
    }

    private void validateBillContacter(String billContacterName) {
        if (StrUtil.isNotBlank(billContacterName) && adminUserMapper.selectOne(AdminUserDO::getNickname, billContacterName) == null) {
            throw exception(USER_NOT_EXISTS);
        }
    }

    private void validateSettlement(String settlementName) {
        if (StrUtil.isNotBlank(settlementName) && orderMethodMapper.selectOne(OrderMethodDO::getName, settlementName) == null) {
            throw exception(ORDER_METHOD_NOT_EXISTS);
        }
    }

    @Override
    public SaleOrderDO getSaleOrder(Long id) {
        SaleOrderDO saleOrderDO = saleOrderMapper.selectById(id);
        if (saleOrderDO == null) {
            throw exception(SALE_ORDER_NOT_EXISTS);
        }
        List<AdminUserDO> adminUserDOS = adminUserMapper.selectBatchIds(Arrays.asList(Long.parseLong(saleOrderDO.getCreator()),Long.parseLong(saleOrderDO.getUpdater())));
        if (adminUserDOS.size() > 1) {
            saleOrderDO.setCreator(adminUserDOS.get(0).getNickname());
            saleOrderDO.setUpdater(adminUserDOS.get(1).getNickname());
        }else if (adminUserDOS.size() == 1){
            saleOrderDO.setUpdater(adminUserDOS.get(0).getNickname());
            saleOrderDO.setCreator(adminUserDOS.get(0).getNickname());
        }
        return saleOrderDO;
    }

    @Override
    public PageResult<SaleOrderDO> getSaleOrderPage(SaleOrderPageReqVO pageReqVO) {
        return saleOrderMapper.selectSaleOrderPage(pageReqVO);
    }

    /**
     * @param pageReqVO:
      * @return PageResult<SaleOrderDO>
     * @author Max-u-19
     * @description 分页查询订单，增加显示订单包含的物品和数量 （暂时弃用，改用增加冗余字段的方式,即默认查询）
     * @date 2024/1/23 13:11
     */
    @Override
    public PageResult<SaleOrderRespVO> getSaleOrderWithGoodsPage(SaleOrderPageReqVO pageReqVO) {
        PageResult<SaleOrderDO> saleOrderDOPageResult = saleOrderMapper.selectSaleOrderPage(pageReqVO);
        PageResult<SaleOrderRespVO> saleOrderRespVOPageResult = BeanUtils.toBean(saleOrderDOPageResult, SaleOrderRespVO.class);
        List<SaleOrderRespVO> saleOrderRespVOS = saleOrderRespVOPageResult.getList();
        saleOrderRespVOS.forEach(saleOrderVO ->{
            List<SaleOrderGoodsDO> saleOrderGoodsDOS = saleOrderGoodsMapper.selectListByOrderId(saleOrderVO.getId());
            saleOrderVO.setSaleOrderGoodsDOS(ErpSaleOrderGoodsConvert.INSTANCE.convertDOList(saleOrderGoodsDOS));
        });
        saleOrderRespVOPageResult.setList(saleOrderRespVOS);
        return saleOrderRespVOPageResult;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public SaleOrderImportRespVO importSaleOrderList(List<SaleOrderImportExcelVO> importSaleOrders, boolean isUpdateSupport, Long userId) {
        if (CollUtil.isEmpty(importSaleOrders)) {
            throw exception(SALE_ORDER_IMPORT_LIST_IS_EMPTY);
        }
        SaleOrderImportRespVO respVO = SaleOrderImportRespVO.builder().createSaleOrdernames(new ArrayList<>())
                .updateSaleOrdernames(new ArrayList<>()).failureSaleOrdernames(new LinkedHashMap<>()).build();
        // 因为可能会出现重复的销售单号，但是第一次商品成功添加，第二次因为是否更新{isUpdateSupport}为false拦截
        Map<String, Boolean> map = new ConcurrentHashMap<>();
        importSaleOrders.forEach(importSaleOrder ->{
            // 没有销售单号使用默认单号
            if (StrUtil.isBlank(importSaleOrder.getBillNo())) {
//                importSaleOrder.setBillNo(sequenceService.nextSequence("XS"));
                importSaleOrder.setBillNo(noRedisDAO.generate(ErpNoRedisDAO.SALE_ORDER_NO_PREFIX));
                map.put(importSaleOrder.getBillNo(), true);
            } else {
                map.put(importSaleOrder.getBillNo(), saleOrderMapper.selectByNo(importSaleOrder.getBillNo()) == null);
            }
        });
        // 导入销售订单信息
        importSaleOrders.forEach(importSaleOrder ->{
            try {
                validateSaleOrder(importSaleOrder, isUpdateSupport, map);
            } catch (ServiceException ex) {
                respVO.getFailureSaleOrdernames().put(importSaleOrder.getBillNo(), ex.getMessage());
                return;
            }

            // 填充多表连接参数
            SaleOrderDO saleOrderDO = BeanUtils.toBean(importSaleOrder, SaleOrderDO.class);
            if (StrUtil.isNotBlank(importSaleOrder.getBillContacterName())) {
                saleOrderDO.setBillContacterMobile(adminUserMapper.selectOne(AdminUserDO::getNickname, importSaleOrder.getBillContacterName()).getMobile());
            }
            if (StrUtil.isNotBlank(importSaleOrder.getWarehouseName())) {
                saleOrderDO.setWarehouseId(Math.toIntExact(warehouseMapper.selectOne(WarehouseDO::getName, importSaleOrder.getWarehouseName()).getId()));
            }
            if (StrUtil.isNotBlank(importSaleOrder.getCustomerName())) {
                saleOrderDO.setCustomerId(crmCustomerMapper.selectOne(CrmCustomerDO::getName, importSaleOrder.getCustomerName()).getId());
            }
            if (StrUtil.isNotBlank(importSaleOrder.getProjectName())) {
                saleOrderDO.setProjectId(Math.toIntExact(orderProjectMapper.selectOne(OrderProjectDO::getName, importSaleOrder.getProjectName()).getId()));
            }
            if (StrUtil.isNotBlank(importSaleOrder.getSettlementName())) {
                saleOrderDO.setSettlementId(Math.toIntExact(orderMethodMapper.selectOne(OrderMethodDO::getName, importSaleOrder.getSettlementName()).getId()));
            }

            // 判断如果不存在，插入
            SaleOrderDO existSaleOrder = saleOrderMapper.selectByNo(importSaleOrder.getBillNo());
            if (existSaleOrder == null) {
                saleOrderDO.setAggregateQuantity(BigDecimal.ZERO);
                saleOrderDO.setAggregateAmount(BigDecimal.ZERO);
                saleOrderDO.setTotalAmount(BigDecimal.ZERO);
                saleOrderMapper.insert(saleOrderDO);
                saveSaleOrderGoods(saleOrderDO, importSaleOrder);
                respVO.getCreateSaleOrdernames().add(saleOrderDO.getBillNo());
                return;
            }

            // 如果存在，判断是否允许更新
            if (!isUpdateSupport && !map.get(importSaleOrder.getBillNo())) {
                respVO.getFailureSaleOrdernames().put(importSaleOrder.getBillNo(), SALE_ORDER_EXISTS.getMsg());
                return;
            }
            saleOrderDO.setId(existSaleOrder.getId());
            saleOrderDO.setAggregateAmount(existSaleOrder.getAggregateAmount());
            saleOrderDO.setAggregateQuantity(existSaleOrder.getAggregateQuantity());
            saleOrderDO.setTotalAmount(existSaleOrder.getTotalAmount());
            saleOrderMapper.updateById(saleOrderDO);
            saveSaleOrderGoods(saleOrderDO, importSaleOrder);
            respVO.getUpdateSaleOrdernames().add(importSaleOrder.getBillNo());
        });
        return respVO;
    }

    private void saveSaleOrderGoods(SaleOrderDO saleOrderDO, SaleOrderImportExcelVO importSaleOrder) {
        // 添加商品
        SaleOrderGoodsDO saleOrderGoodsDO = saleOrderGoodsMapper.selectOne(SaleOrderGoodsDO::getCode, importSaleOrder.getCode(), SaleOrderGoodsDO::getOrderId, saleOrderDO.getId());
        boolean flag = false;
        if (saleOrderGoodsDO == null) {
            saleOrderGoodsDO = new SaleOrderGoodsDO();
            flag = true;
        } else {
            saleOrderDO.setAggregateQuantity(saleOrderDO.getAggregateQuantity().subtract(saleOrderGoodsDO.getNumber()));
            saleOrderDO.setAggregateAmount(saleOrderDO.getAggregateAmount().subtract(saleOrderGoodsDO.getPrice().multiply(saleOrderGoodsDO.getNumber())));
        }
        saleOrderGoodsDO.setOrderId(saleOrderDO.getId());
        GoodsDO goodsDO = goodsMapper.selectByCode(importSaleOrder.getCode());
        saleOrderGoodsDO.setGoodsId(goodsDO.getId());
        saleOrderGoodsDO.setName(goodsDO.getName());
        saleOrderGoodsDO.setCode(goodsDO.getCode());
        saleOrderGoodsDO.setModels(goodsDO.getModels());
        saleOrderGoodsDO.setNameEn(goodsDO.getNameEn());
        saleOrderGoodsDO.setNumber(importSaleOrder.getNumber());
        saleOrderGoodsDO.setTaxRate(importSaleOrder.getTaxRate());
        BigDecimal price = importSaleOrder.getPrice();
        BigDecimal taxRate = importSaleOrder.getTaxRate().divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP);
        BigDecimal number = importSaleOrder.getNumber();
        // 计算未含税单价
        BigDecimal noTaxPrice = price.divide (taxRate.add(BigDecimal.ONE),2, RoundingMode.HALF_UP);
        saleOrderGoodsDO.setNoTaxPrice(noTaxPrice);
        // 计算未含税总额
        BigDecimal noTaxTotal = noTaxPrice.multiply(number);
        saleOrderGoodsDO.setNoTaxTotal(noTaxTotal);
        // 计算总金额（价税总额）
        BigDecimal total = price.multiply(number);
        saleOrderGoodsDO.setTotal(total);
        // 根据已知的总金额和未含税总额计算税额
        BigDecimal tax = total.subtract(noTaxTotal);
        saleOrderGoodsDO.setTax(tax);
        saleOrderGoodsDO.setPrice(importSaleOrder.getPrice());
        saleOrderGoodsDO.setUnitCost(importSaleOrder.getUnitCost());
        saleOrderGoodsDO.setDeliveryData(importSaleOrder.getDeliveryData());
        saleOrderGoodsDO.setOutNum(importSaleOrder.getOutNum());
        saleOrderGoodsDO.setInNum(importSaleOrder.getInNum());
        saleOrderGoodsDO.setNoOutNum(importSaleOrder.getNoOutNum());
        saleOrderGoodsDO.setPlanNum(importSaleOrder.getPlanNum());
        saleOrderGoodsDO.setWorkNum(importSaleOrder.getWorkNum());
        saleOrderGoodsDO.setRemarks(importSaleOrder.getGoodRemarks());
        if (flag) {
            saleOrderGoodsMapper.insert(saleOrderGoodsDO);
        } else {
            saleOrderGoodsMapper.updateById(saleOrderGoodsDO);
        }
        // 计算 saleOrderDO 的总数量 总金额  优惠金额  优惠后的总金额
        try {
            saleOrderDO.setGoodsInfo(objectMapper.writeValueAsString(saleOrderGoodsMapper.selectListByOrderId(saleOrderDO.getId())));
        } catch (JsonProcessingException e) {
            throw exception(GOODS_CONVERT_FAIL);
        }
        saleOrderDO.setAggregateQuantity(saleOrderDO.getAggregateQuantity().add(importSaleOrder.getNumber()));
        saleOrderDO.setAggregateAmount(saleOrderDO.getAggregateAmount().add(importSaleOrder.getPrice().multiply(importSaleOrder.getNumber())));
        saleOrderDO.setDiscountAmount(saleOrderDO.getAggregateAmount().subtract(importSaleOrder.getDiscountAmount()).compareTo(BigDecimal.ZERO)<=0?saleOrderDO.getAggregateAmount():importSaleOrder.getDiscountAmount());
        saleOrderDO.setTotalAmount(saleOrderDO.getAggregateAmount().subtract(saleOrderDO.getDiscountAmount()));
        saleOrderMapper.updateById(saleOrderDO);
    }

    @Override
    public BigDecimal getSumSaleOrderAmount(){
        List<SaleOrderDO> saleOrderDOS = saleOrderMapper.selectAmountTotal(0);
        return saleOrderDOS.stream().map((value) -> {
            if (value.getTotalAmount() != null) {
                return value.getTotalAmount();
            }
            return BigDecimal.ZERO;
        }).reduce(BigDecimal.ZERO,BigDecimal::add);
    }

    /**
     * @param no:
      * @return Boolean
     * @author Max-u-19
     * @description 校验订单号是否唯一
     * @date 2024/2/3 20:42
     */
    @Override
    public Boolean checkSaleOrderNoUnique(String no) {
        SaleOrderDO saleOrderDO = saleOrderMapper.selectByNo(no);
        return saleOrderDO != null;
    }
    // ==================== 子表（销售单和物品的链接表-多对多关系） ====================

    @Override
    public List<SaleOrderGoodsRespVO> getSaleOrderGoodsListByOrderId(Long orderId) {
        List<SaleOrderGoodsDO> saleOrderGoodsDOS = saleOrderGoodsMapper.selectListByOrderId(orderId);
        if (CollectionUtils.isEmpty(saleOrderGoodsDOS)) {
            throw exception(SALEORDERGOODS_NOT_EXIST);
        }
        List<SaleOrderGoodsRespVO> saleOrderGoodsRespVOS = BeanUtils.toBean(saleOrderGoodsDOS, SaleOrderGoodsRespVO.class);
        List<GoodsDO> goodsDOS = goodsMapper.selectBatchIds(convertList(saleOrderGoodsRespVOS, SaleOrderGoodsRespVO::getGoodsId));
        Map<Long, GoodsDO> goodsDOMap = convertMap(goodsDOS, GoodsDO::getId);
        saleOrderGoodsRespVOS.forEach(saleOrderGoodsRespVO -> {
            GoodsDO goodsDO = goodsDOMap.get(saleOrderGoodsRespVO.getGoodsId());
            saleOrderGoodsRespVO.setBrand(goodsDO.getBrand());
            saleOrderGoodsRespVO.setModels(goodsDO.getModels());
            saleOrderGoodsRespVO.setProBarCode(goodsDO.getProBarCode());
            saleOrderGoodsRespVO.setNameEn(goodsDO.getNameEn());
            saleOrderGoodsRespVO.setUnit(goodsDO.getUnit());
            List<GoodsWarehouseLinkDO> goodsWarehouseLinkDOS = inventoryMapper.selectListByGoodsId(saleOrderGoodsRespVO.getGoodsId());
            BigDecimal inventoryTotal = goodsWarehouseLinkDOS.stream().map(GoodsWarehouseLinkDO::getInventory).reduce(BigDecimal.ZERO, BigDecimal::add);
            saleOrderGoodsRespVO.setInventoryTotal(inventoryTotal);
            List<SaleOrderGoodsRespVO.InventoryItem> inventoryItems = ErpGoodsWarehouseLinkConvert.INSTANCE.convertToInventoryItemList(goodsWarehouseLinkDOS);
            List<WarehouseDO> warehouseDOS = warehouseMapper.selectBatchIds(convertList(inventoryItems, SaleOrderGoodsRespVO.InventoryItem::getWarehouseId));
            Map<Long, WarehouseDO> warehouseDOMap = convertMap(warehouseDOS, WarehouseDO::getId);
            inventoryItems.forEach(item -> {
                WarehouseDO warehouseDO = warehouseDOMap.get(item.getWarehouseId());
                item.setWarehouseName(warehouseDO.getName());
            });
            saleOrderGoodsRespVO.setInventoryList(inventoryItems);
        });
        return saleOrderGoodsRespVOS;
    }



    private void createSaleOrderGoodsList(Long orderId, List<SaleOrderGoodsDO> list) {
        list.forEach(o -> o.setOrderId(orderId).setId(null).setOutNum(BigDecimal.ZERO).setNoOutNum(o.getNumber()));
        saleOrderGoodsMapper.insertBatch(list);
    }

    private void updateSaleOrderGoodsList(Long orderId, List<SaleOrderGoodsDO> list) {
        deleteSaleOrderGoodsByOrderId(orderId);
        list.forEach(o -> o.setId(null).setUpdater(null).setUpdateTime(null)); // 解决更新情况下：1）id 冲突；2）updateTime 不更新
        createSaleOrderGoodsList(orderId, list);
    }

    private void deleteSaleOrderGoodsByOrderId(Long orderId) {
        saleOrderGoodsMapper.deleteByOrderId(orderId);
    }

    private void deleteAnySaleOrderGoodsByOrderId(Collection<Long> orderIds) {
        saleOrderGoodsMapper.deleteByOrderIds(orderIds);
    }

    private void validateSaleOrder(SaleOrderImportExcelVO saleOrderImportExcelVO, boolean isUpdateSupport, Map<String, Boolean> map) {
        DataPermissionUtils.executeIgnore(() -> {
            // 校验销售单号
            validateSaleOrderBillNoUnique(saleOrderImportExcelVO.getBillNo(), isUpdateSupport, map);
            // 校验仓库名称（仓库名称必填）
            validateWarehouseName(saleOrderImportExcelVO.getWarehouseName());
            // 校验客户
            validateCustomer(saleOrderImportExcelVO.getCustomerName());
            // 校验商品
            validateGoods(saleOrderImportExcelVO.getCode());
            // 校验税率
            validateTaxRate(saleOrderImportExcelVO.getTaxRate());
            // 校验项目
            validateProject(saleOrderImportExcelVO.getProjectName());
            // 校验销售员
            validateBillContacter(saleOrderImportExcelVO.getBillContacterName());
            // 校验结算方式
            validateSettlement(saleOrderImportExcelVO.getSettlementName());
        });
    }

}